/*
** Copyright (c) 2008 Mobile GCalendarManager
**
** Permission is hereby granted, free of charge, to any person
** obtaining a copy of this software and associated documentation
** files (the "Software"), to deal in the Software without
** restriction, including without limitation the rights to use,
** copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the
** Software is furnished to do so, subject to the following
** conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
** HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
** OTHER DEALINGS IN THE SOFTWARE.
*/

/**
 *
 */
package au.edu.mq.comp.itec800.mgc.util;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InvalidPropertiesFormatException;
import java.util.List;
import java.util.Properties;

/**
 * The Configuration class serves as a lightweight text-based
 * settings management facility.
 *
 * Based on the standard Properties class, it can load XML or normal
 * properties files and provides classes to merge properties or create a
 * Configuration object from a file, or update it at runtime.
 *
 * It also provides method to get properties safely (sget(String)) and set
 * default values (setDefault(String, String)).
 *
 *
 * @see Properties
 *
 * @author Laurent Malvert [laurent.malvert@students.mq.edu.au]
 */
public class Configuration extends Properties
{
  private static final long   serialVersionUID  = -2277958657381951036L;
  private static final String LOAD_ERROR        = "could not load properties file [%s]".intern();

  private List<String>        arguments         = new ArrayList<String>();


  public static class ConfigurationException extends Exception
  {
    private static final long serialVersionUID = 6582009694933640513L;


    public ConfigurationException()
    {
      super();
    }

    public ConfigurationException(final String message)
    {
      super(message);
    }

    public ConfigurationException(final Exception cause)
    {
      super(cause);
    }

    public ConfigurationException(final String message,
                                  final Exception cause)
    {
      super(message, cause);
    }
  }

  public Configuration()
  {
    super();
  }

  public Configuration(final Properties defaults)
  {
    super(defaults);
  }

  public Properties                     mergeProperties(final Properties properties)
  {
    if (properties != null)
    {
      putAll(properties);
    }
    return (properties);
  }

  public void                           loadFromXML(final String file)
    throws ConfigurationException
  {
    try
    {
      super.loadFromXML(new FileInputStream(file));
    }
    catch (final InvalidPropertiesFormatException e)
    {
      throw failure(String.format(LOAD_ERROR, file), e);
    }
    catch (final FileNotFoundException e)
    {
      throw failure(String.format(LOAD_ERROR, file), e);
    }
    catch (final IOException e)
    {
      throw failure(String.format(LOAD_ERROR, file), e);
    }
  }

  public static Configuration           createFromXML(final String file)
    throws ConfigurationException
  {
    final Configuration                 config = new Configuration();

    config.loadFromXML(file);
    return (config);
  }

  public boolean                        check(final String key,
                                              final String cmp)
  {
    final String                        k = StringUtils.clean(key);

    return (containsKey(k) &&
            getProperty(k).equalsIgnoreCase(StringUtils.clean(cmp)));
  }

  public static Configuration           createFromProperties(final String file)
    throws ConfigurationException, IOException
  {
    final Configuration                 config  = new Configuration();

    try
    {
      config.load(new FileReader(file));
    }
    catch (final FileNotFoundException e)
    {
      throw failure(String.format(LOAD_ERROR, file), e);
    }
    catch (final NullPointerException e)
    {
      throw failure(String.format(LOAD_ERROR, file), e);
    }
    return (config);
  }

  private static ConfigurationException failure(final String message,
                                                final Exception e)
  {
    return (new ConfigurationException(message, e));
  }

  public String                         toPath(final String ... keys)
  {
    final StringBuffer                  path  = new StringBuffer();

    if (keys != null)
    {
      final int size  = keys.length;

      for (int i = 0; i < size; i++)
      {
        path.append(getProperty(keys[i]));
        if (i < (keys.length - 1))
        {
          path.append("/");
        }
      }
    }
    return (path.toString());
  }

  public String                         sget(final String key)
  {
    return (StringUtils.sanitize(getProperty(key)));
  }


  /**
   * Sets a default configuration setting.
   *
   *  If the setting already has a value, we leave it unchanged, otherwise
   *  we use the default value given has argument.
   *
   * @param key
   *            the property key to be looked up
   * @param defaultValue
   *            the default value to be set up if no previous value exists
   */
  public void                           setDefault(final String key,
                                                   final String defaultValue)
  {
    if (contains(key) == false)
    {
      setProperty(key, defaultValue);
    }
  }

  public void                           setArguments(final String[] args)
  {
    arguments.clear();
    if ((args != null) && (args.length > 0))
    {
      arguments.addAll(Arrays.asList(args));
    }
  }

  public List<String>                   getArguments()
  {
    return (arguments);
  }

  @Override
  public String                         toString()
  {
    return (super.toString().replaceAll("\\{", "\\{\n ")
                            .replaceAll(", ", "\n ")
                            .replaceAll("\\}", "\n\\}"));
  }
}
